/*
 * Graphical.java
 *
 * Created on 18 maart 2008, 14:47
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */
package model.graphic.objects;

import controller.commands.ClearSelectionCommand;
import controller.commands.SetSelectedCommand;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.io.Serializable;
import javax.swing.JComponent;
import model.graphic.interfaces.Draggable;
import model.graphic.interfaces.Highlightable;
import model.graphic.locations.Location;
import view.GUI.sidepanels.CustomArgument;
import view.GUI.graphic.GraphicView;

/**
 *
 * @author wijnand.schepens@hogent.be
 */
public abstract class Graphical extends JComponent implements MouseListener, MouseMotionListener, Highlightable, Draggable, Serializable, Cloneable {

    private int selectedlevel;
    private int layerlevel;
    protected String name = "NoName";
    protected String type = "NoType";
    protected boolean highlighted = false;
    protected boolean selected = false;
    protected Location location;
    protected Color baseColor = Color.BLACK;
    protected Color backColor = Color.WHITE;
    protected Color highlightColor = Color.RED;
    protected Point dragStartPoint;
    protected Point dragEndPoint;

    public Graphical() {
        this.addMouseListener(this);
        this.addMouseMotionListener(this);
    }

    public abstract void paint(Graphics2D g);

    public void mouseClicked(MouseEvent e) {
    }

    public void mousePressed(MouseEvent e) {
        this.dragStartPoint = e.getPoint();
        this.dragEndPoint = e.getPoint();
        GraphicView gv = (GraphicView) this.getParent();
        if (!e.isControlDown()) {
            gv.notifyObservers(new ClearSelectionCommand());
            gv.notifyObservers(new SetSelectedCommand(this, true));
        } else {
            if (!this.isSelected()) {
                gv.notifyObservers(new SetSelectedCommand(this, true));
            } else {
                gv.notifyObservers(new SetSelectedCommand(this, false));
            }
        }
        gv.notifyObservers(new CustomArgument("tabRight", 0));
    }

    public void mouseReleased(MouseEvent e) {
        GraphicView gv = (GraphicView) this.getParent();
        gv.notifyObservers(new SetSelectedCommand(this, true));
    }

    public void mouseEntered(MouseEvent e) {
        this.setHighlighted(true);
        this.setLocation(this.getGraphLocation());
        GraphicView gv = (GraphicView) this.getParent();
        gv.repaint();
    }

    public void mouseExited(MouseEvent e) {
        this.setHighlighted(false);
        if (RectangleGraphical.class.isAssignableFrom(this.getClass())) {
            ((RectangleGraphical) this).getRemoveAddon().setAddonHighlighted(false);
            ((RectangleGraphical) this).getShrinkAddon().setAddonHighlighted(false);
            if (GBoxNode.class.isAssignableFrom(this.getClass())) {
                ((GBoxNode) this).getZoomAddon().setAddonHighlighted(false);
            }
        }
        GraphicView gv = (GraphicView) this.getParent();
        gv.repaint();
    }

    public void mouseDragged(MouseEvent e) {
        //throw new UnsupportedOperationException("Not supported yet.");
    }

    public void mouseMoved(MouseEvent e) {
    }

    @Override
    public Graphical clone() {
        Graphical copy;
        try {
            copy = (Graphical) super.clone();
            copy.removeMouseListener(this);
            copy.removeMouseMotionListener(this);
            copy.addMouseListener(copy);
            copy.addMouseMotionListener(copy);
        } catch (CloneNotSupportedException unexpected) {
            throw new AssertionError(unexpected);
        }
        return copy;
    }
    public boolean isContainedIn(Rectangle rect) {
        return rect.contains(location.getX(), location.getY());
    }

    public void drag(int relX, int relY) {
        location.setXY(location.getX() + relX, location.getY() + relY);
    }

    public Location getGraphLocation() {
        return location;
    }

    public void setLocation(Location location) {
        this.location = location;
        if (location != null) {
            try {
                int x = location.getX();
                int y = location.getY();
                int w = this.getWidth();
                int h = this.getHeight();
                setBounds(x, y, w, h);
            } catch (Exception exc) {
                //System.out.println("No Location Yet!");
            }
        }

    }

    public void setSelected(boolean selected) {
        this.selected = selected;
        if (selected) {
            this.setSelectedLevel(0);
        } else {
            this.setSelectedLevel(this.getLayerLevel());
        }
    }

    /**
     * @return the level
     */
    public int getSelectedLevel() {
        return selectedlevel;
    }

    /**
     * @param level the level to set
     */
    public void setSelectedLevel(int level) {
        this.selectedlevel = level;
    }

    public int getLayerLevel() {
        return layerlevel;
    }

    /**
     * @param level the level to set
     */
    public void setLayerLevel(int level) {
        this.layerlevel = level;
        this.selectedlevel = level;
    }

    /**
     * @return the name
     */
    public String getName() {
        return name;
    }

    /**
     * @param name the name to set
     */
    public void setName(String name) {
        this.name = name;
    }

    /**
     * @return the baseColor
     */
    public Color getBaseColor() {
        return baseColor;
    }

    /**
     * @param baseColor the baseColor to set
     */
    public void setBaseColor(Color baseColor) {
        this.baseColor = baseColor;
    }

    public void setHighLightColor(Color color) {
        highlightColor = color;
    }

    /**
     * @return the backColor
     */
    public Color getBackColor() {
        return backColor;
    }

    /**
     * @param backColor the backColor to set
     */
    public void setBackColor(Color backColor) {
        this.backColor = backColor;
    }

    public Color getHighlightColor() {
        return highlightColor;
    }

    public boolean isHighlighted() {
        return highlighted;
    }

    public void setHighlighted(boolean highlighted) {
        this.highlighted = highlighted;
    }

    /**
     * @return the type
     */
    public String getType() {
        return type;
    }

    /**
     * @param type the type to set
     */
    public void setType(String type) {
        this.type = type;
    }

    /**
     * @return the selected
     */
    public boolean isSelected() {
        return selected;
    }

    public String toString(){
        return this.getName();
    }
}
